package com.lijin.workshop.web.action;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.apache.struts2.json.JSONUtil;

import com.lijin.workshop.cache.ColumnConfCache;
import com.lijin.workshop.entity.ColumnInfo;
import com.lijin.workshop.entity.Pager;


/**
 * @author jin
 *	
 * 有增删改查操作的Action的基类
 * 提供了增删改查的处理流程模板，具体业务实现由业务子类完成
 * * 查询：翻页查询结果以JSON形式传至前台
 * * 新增、修改、删除操作，都以AJAX形式进行，操作结果只有两个: succ-成功，fail-失败
 * 
 * 如果各业务类想自己实现，可直接继承BaseAction，自主实现
 *
 */
public abstract class CRUDAction<T> extends BaseAction {

	private static final long serialVersionUID = 1L;
	private static final Logger logger = Logger.getLogger(CRUDAction.class);
	
	protected boolean qryByPage = true; // 是否进行分页查询，默认分页，也可指定不分页
	
	/**
	 * 跳转至管理主页面
	 * @return
	 */
	public String manage() {
		prepareData();
		return RESULT_MANAGE;
	}
	/**
	 * 跳转至管理主页面时如果需要预先准备一些数据，复写本方法实现
	 */
	protected void prepareData() { }

	/*******************查询操作流程模板**************************/
	/**
	 * 查询操作模板，流程如下：
	 * 
	 * 1. 根据子类重写getColumnType()方法提供的列类型，来构造查询结果列信息，
	 * 	      列信息包括：显示那些列、每一列的中文描述、每列的宽度，这些都是根据column.conf配置文件配置的
	 * 2. 子类重写qryResult()方法实现具体的查询功能，并返回查询结果分页对象
	 * 3. 调用方法transformQryResult()将查询结果列表中每个实体类转成Map
	 * 4. 将实体类转成Map时，如需对某些字段进行转义，或添加自定义信息，可以由子类重写transformEntity()方法来实现
	 * 5. 将列信息、转换后的查询结果信息、分页信息已JSON字符串形式返回值前台页面
	 * 6. 前台页面根据返回的结果来自动构造翻页列表
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String qry() {
		try {
			ColumnConfCache c = ColumnConfCache.getInstance();
			List<ColumnInfo> columns = c.getColumnLst(this.getColumnType());
			
			// 初始化分页信息，如果查询模式不是分页查询，则都为0
			int pageNum = 0;
			int pageSize = 0;
			int total = 0;
			
			List<T> resultLst = null;
			// 如果当前查询模式是分页查询,则进行分页查询
			if (qryByPage) {
				Pager<T> p = qryResultByPage();
				resultLst = p.getResultList();
				pageNum = p.getPageNum();
				pageSize = p.getPageSize();
				total = p.getTotal();
			} else {
				resultLst = this.qryResultLst();
			}
			List<Map> resultMap = transformQryResult(resultLst);
			
			/**
			 * 构造返回结果JSON字符串
			 */
			StringBuilder jsonResult = new StringBuilder();
			jsonResult.append("{\"result\":\"" + AJAX_RESULT_SUCC + "\"");
			jsonResult.append(",\"pageNum\":" + pageNum);
			jsonResult.append(",\"pageSize\":" + pageSize);
			jsonResult.append(",\"total\":" + total);
			jsonResult.append(",\"columns\":");
			jsonResult.append(JSONUtil.serialize(columns));
			jsonResult.append(",\"rows\":");
			jsonResult.append(JSONUtil.serialize(resultMap));
			jsonResult.append("}");
			ajaxResult = jsonResult.toString();
		} catch (Exception e) {
			logger.error("查询出错", e);
			// 如果查询操作失败，构造失败信息，并返回失败原因
			ajaxResult = this.buildJSONResp(AJAX_RESULT_FAIL, e.getMessage());;
		}
		return AJAX_RESULT_TYPE;
	}
	/**
	 * 用于构造查询结果列信息，子类可根据情况返回相应类型
	 * @return
	 */
	protected abstract String getColumnType();
	/**
	 * 分页查询，由子类具体实现
	 * @return
	 */
	protected Pager<T> qryResultByPage() {return null;}
	/**
	 * 查询不分页，由子类具体实现
	 * @return
	 */
	protected List<T> qryResultLst() {return null;}
	
	/**
	 * 对查询结果进行转换，查询结果列表中每个对象都是相应的实体类，在本方法中都转成Map
	 * @param qryResultLst
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<Map> transformQryResult(List<T> qryResultLst) {
		List<Map> lst = new ArrayList<Map>();
		if (qryResultLst != null) {
			for (T o : qryResultLst) {
				try {
					Map m = BeanUtils.describe(o);
					// 如果要进行转义或者增加个性化信息，在这个方法里实现
					transformEntity(m);
					lst.add(m);
				} catch (Exception e) {
					logger.error("转换查询结果失败", e);
				}
			}
		}
		return lst;
	}
	/**
	 * 用于对查询结果进行转换，当需要对查询结果进行转义时可复写本方法
	 * 可以向查询结果实体对应的map中填入任意信息，然后在列信息配置中配置进去即可自动显示
	 * @param m
	 */
	@SuppressWarnings("unchecked")
	protected void transformEntity(Map m) {}
	
	/*******************新增操作流程模板**************************/
	/**
	 * 新增操作模板
	 * @return
	 */
	public String add() {
		try {
			validateAddImpl();
			addImpl();
			// 构造成功结果信息
			ajaxResult = this.buildJSONResp(AJAX_RESULT_SUCC, null);
		} catch (Exception e) {
			logger.error("新增操作失败", e);
			// 如果新增操作失败，构造失败信息，并返回失败原因
			ajaxResult = this.buildJSONResp(AJAX_RESULT_FAIL, e.getMessage());
		}
		return AJAX_RESULT_TYPE;
	}
	/**
	 * 执行新增操作之前先进行校验，由业务子类实现
	 */
	protected void validateAddImpl() { };
	/**
	 * 新增操作，由业务子类提供具体实现
	 */
	protected void addImpl() { }
	
	/*******************更新操作流程模板**************************/
	/**
	 * 更新操作模板
	 * @return
	 */
	public String update() {
		try {
			validateUpdateImpl();
			updateImpl();
			// 构造成功信息
			ajaxResult = AJAX_RESULT_SUCC;
		} catch (Exception e) {
			logger.error("更新操作失败", e);
			// 如果更新操作失败，构造失败信息，并返回失败原因
			ajaxResult = this.buildJSONResp(AJAX_RESULT_FAIL, e.getMessage());
		}
		return AJAX_RESULT_TYPE;
	}
	/**
	 * 执行更新操作之前先进行校验，由业务子类提供实现
	 */
	protected void validateUpdateImpl() {}
	/**
	 * 更新操作，由业务子类提供具体实现
	 */
	protected void updateImpl() {}
	
	/*******************删除操作流程模板**************************/
	/**
	 * 删除操作模板方法
	 * @return
	 */
	public String delete() {
		try {
			// 执行删除
			validateDeleteImpl();
			deleteImpl();
			ajaxResult = AJAX_RESULT_SUCC;
		} catch (Exception e) {
			ajaxResult = AJAX_RESULT_FAIL;
		}
		return AJAX_RESULT_TYPE;
	}
	/**
	 * 执行删除操作之前先进行校验，由业务子类提供实现
	 */
	protected void validateDeleteImpl() { }
	/**
	 * 删除操作，由业务子类提供具体实现
	 */
	protected void deleteImpl() { }
	
	public boolean isQryByPage() {
		return qryByPage;
	}
	public void setQryByPage(boolean qryByPage) {
		this.qryByPage = qryByPage;
	}
}

